<?php
/*--------------------------------------------------------------
   GambioAssetUrlReplacer.php 2025-12-11
   Gambio GmbH
   http://www.gambio.de
   Copyright (c) 2025 Gambio GmbH
   Released under the GNU General Public License (Version 2)
   [http://www.gnu.org/licenses/gpl-2.0.html]
 -------------------------------------------------------------*/

declare(strict_types=1);

namespace Gambio\Admin\Modules\Dashboard\Html;

/**
 * Class GambioAssetUrlReplacer
 *
 * Replaces JS, CSS and font asset URLs from Gambio domains with local proxy URLs.
 * Only URLs from gambio.de or gambio.com (with any subdomain) are replaced for security.
 *
 * @package Gambio\Admin\Modules\Dashboard\Html
 */
class GambioAssetUrlReplacer
{
    /**
     * @var string
     */
    private string $proxyEndpoint;

    /**
     * Allowed file extensions for proxying.
     */
    private const ALLOWED_FILE_EXTENSIONS = ['js', 'css', 'woff', 'woff2', 'ttf', 'eot', 'otf'];

    /**
     * Pattern matches gambio.de or gambio.com domain (with any subdomain).
     * Used for domain validation.
     */
    private const GAMBIO_DOMAIN_PATTERN = '(?:[a-z0-9-]+\.)?gambio\.(?:de|com)';

    /**
     * Pattern matches JS, CSS and font URLs from any gambio.de or gambio.com subdomain.
     * Examples:
     *   - https://www.gambio.de/files/admin-news/js/axios.min.js
     *   - https://dashboard.gambio.de/files/admin-news/css/style.css
     *   - https://gambio.com/files/admin-news/js/Chart.min.js
     *   - http://gambio.de/path/to/font.woff2
     */
    private const GAMBIO_ASSET_URL_PATTERN = '#(https?://' . self::GAMBIO_DOMAIN_PATTERN . '/[^"\'>\s]+\.(?:js|css|woff2?|ttf|eot|otf))#i';


    /**
     * GambioAssetUrlReplacer constructor.
     *
     * @param string $proxyEndpoint The local proxy endpoint path (e.g., 'dashboard/resource')
     */
    public function __construct(string $proxyEndpoint = 'dashboard/resource')
    {
        $this->proxyEndpoint = $proxyEndpoint;
    }


    /**
     * Replaces all Gambio JS and CSS URLs in the given HTML with local proxy URLs.
     *
     * @param string $html The HTML content to process
     * @return string The HTML with replaced URLs
     */
    public function replace(string $html): string
    {
        return preg_replace_callback(self::GAMBIO_ASSET_URL_PATTERN, function ($matches) {
            return $this->buildProxyUrl($matches[1]);
        }, $html) ?? $html;
    }


    /**
     * Builds a proxy URL for the given original URL.
     * Uses path-based URL structure to support relative imports in JS files.
     *
     * @param string $originalUrl The original asset URL
     * @return string The proxy URL (e.g., dashboard/resource/dashboard.gambio.de/path/file.js)
     */
    public function buildProxyUrl(string $originalUrl): string
    {
        $parsed = parse_url($originalUrl);
        $host   = $parsed['host'] ?? '';
        $path   = $parsed['path'] ?? '';

        return $this->proxyEndpoint . '/' . $host . $path;
    }


    /**
     * Checks if a URL matches the Gambio asset pattern.
     *
     * @param string $url The URL to check
     * @return bool True if the URL is a Gambio JS or CSS asset
     */
    public function isGambioAssetUrl(string $url): bool
    {
        return preg_match(self::GAMBIO_ASSET_URL_PATTERN, $url) === 1;
    }


    /**
     * Extracts all Gambio asset URLs from HTML content.
     *
     * @param string $html The HTML content to scan
     * @return array List of Gambio asset URLs found
     */
    public function extractGambioAssetUrls(string $html): array
    {
        preg_match_all(self::GAMBIO_ASSET_URL_PATTERN, $html, $matches);
        return $matches[1] ?? [];
    }


    /**
     * Checks if a URL is from an allowed Gambio domain.
     *
     * @param string $url The URL to validate
     * @return bool True if the URL is from gambio.de or gambio.com (with any subdomain)
     */
    public static function isAllowedGambioDomain(string $url): bool
    {
        $host = parse_url($url, PHP_URL_HOST);

        if ($host === null || $host === false) {
            return false;
        }

        return preg_match('/^' . self::GAMBIO_DOMAIN_PATTERN . '$/i', $host) === 1;
    }


    /**
     * Checks if the URL points to an allowed file type.
     *
     * @param string $url The URL to validate
     * @return bool True if the file extension is allowed (js, css, fonts)
     */
    public static function isAllowedFileType(string $url): bool
    {
        $path      = parse_url($url, PHP_URL_PATH) ?? '';
        $extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));

        return in_array($extension, self::ALLOWED_FILE_EXTENSIONS, true);
    }
}